/*
 * @Author: 李超越 1509572300@qq.com
 * @Date: 2024-07-09 17:47:07
 * @LastEditors: 李超越 1509572300@qq.com
 * @LastEditTime: 2024-07-23 18:24:30
 * @FilePath: /my_git/lesson20_shell/mytest.c
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>

#define SIZE 1024
#define MAX_ARGC 255
#define SEP " "

char *argv[MAX_ARGC];
char pwd[SIZE];
char env[SIZE];
int lastcode=0;

#define NoneRedir  -1
#define StdinRedir  0
#define StdoutRedir 1
#define AppendRedir 2

int redir_type=NoneRedir;
char* filename=NULL;
#define STREND '\0'

#define IgSpace(buf,pos) do {while(isspace(buf[pos]))pos++;}while(0)

//获取主机名
const char* HostName()
{
	char* hostname=getenv("HOSTNAME");
	if(hostname)
	{
		return hostname;
	}
	return "None";
}

//获取用户名
const char* UserName()
{
	char* hostname=getenv("USER");
	if(hostname)
	{
		return hostname;
	}
	return "None";
}

//获取当前执行路径
const char* CurrentWorkDir()
{
	char* hostname=getenv("PWD");
	if(hostname)
	{
		return hostname;
	}
	return "None";
}

//获取家目录
char* Home()
{
	char* hostname=getenv("HOME");
	if(hostname)
	{
		return hostname;
	}
	return "None";
}

//获取用户输入的命令
int Interactive(char out[])
{
	printf("[%s@%s %s#] ",UserName(),HostName(),CurrentWorkDir());
	fgets(out,SIZE,stdin);
	out[strlen(out)-1]=0;
	return strlen(out);
}

//判断是否是重定向
void CheckRir(char in[])
{
    int pos=strlen(in)-1;
    while(pos>=0)
    {
        if(in[pos]=='>')
        {
            if(in[pos-1]=='>')
            {
                redir_type=AppendRedir;
                in[pos-1]=STREND;
                pos++;
                IgSpace(in,pos);
                filename=in+pos;
                break;
            }
            else
            {
                redir_type=StdoutRedir;
                in[pos++]=STREND;
                IgSpace(in,pos);
                filename=in+pos;
                break;
            }
        }
        else if(in[pos]=='<')
        {
            redir_type=StdinRedir;
            in[pos++]=STREND;
            IgSpace(in,pos); 
            filename=in+pos;
            break;
        }
        else
        {
            pos--;
        }
    }
}

//对命令进行切割，切割出命令和参数
void Split(char in[])
{
    redir_type=NoneRedir;
    filename=NULL;
    CheckRir(in);
	int i=0;
	argv[i++]=strtok(in,SEP);
	while(argv[i++]=strtok(NULL,SEP));
	if(strcmp(argv[0],"ls")==0)
	{
		argv[i-1]=(char*)"--color";
		argv[i]=NULL;
	}
}

//处理内置函数
int BuildinCmd()
{
	int ret=0;
	if(strcmp("cd",argv[0])==0)
	{
		ret=1;
		char* target=argv[1];
		if(!target)
		{
			target=Home();
		}
		chdir(target);
		char temp[SIZE]={0};
		getcwd(temp,SIZE);
		snprintf(pwd,SIZE,"PWD=%s",temp);
		putenv(pwd);
	}
	else if(strcmp("export",argv[0])==0)
	{
		ret=1;
		if(argv[1])
		{
			strcpy(env,argv[1]);
			putenv(env);
		}
	}
	else if(strcmp("echo",argv[0])==0)
	{
		ret=1;
		if(argv[1]==NULL)
		{
			printf("\n");
		}
		else
		{
			if(argv[1][0]=='$')
			{
				if(argv[1][1]=='?')
				{
					printf("%d\n",lastcode);
					lastcode=0;
				}
				else
				{
					char *env=getenv(argv[1]+1);
					if(env)
					{
						printf("%s\n",env);
					}
				}
			}
			else
			{
				printf("%s\n",argv[1]);
			}
		}
	}
	return ret;
}

//执行命令
void Exectue()
{
	pid_t id=fork();
	if(id==0)
	{
        int fd=-1;
        int flag=0;
        if(redir_type=StdinRedir)
        {
            flag |=O_RDONLY;
            fd=open(filename,O_RDONLY);
            dup2(fd,0);
        }
        else if(redir_type=StdoutRedir)
        {
            flag |=O_CREAT|O_WRONLY|O_TRUNC;
            fd=open(filename,O_CREAT|O_WRONLY|O_TRUNC);
            dup2(fd,1);
        }
        else if(redir_type=AppendRedir)
        {
            flag |=O_CREAT|O_WRONLY|O_APPEND;
            fd=open(filename,O_CREAT|O_WRONLY|O_APPEND);
            dup2(fd,1);
        }
        // if(flag&O_RDONLY)
        // {
        //     fd=open(filename,flag,0666);
        //     dup2(fd,0);
        // }
        // else if(flag&O_WRONLY)
        // {
        //     fd=open(filename,flag,0666);
        //     dup2(fd,1);
        // }
		execvp(argv[0],argv);
		exit(1);
	}
	int status=0;
	pid_t rid=waitpid(id,&status,0);
	if(rid==id)
	{
		lastcode=WEXITSTATUS(status);
	}
}

int main()
{
	while(1)
	{
		char commabdline[SIZE];
		int n=Interactive(commabdline);
		if(n==0)
		{
			continue;
		}
		Split(commabdline);
		n=BuildinCmd();
		if(n)
		{
			continue;
		}
		Exectue();
	}
	return 0;
}